home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 3: CDPD 3 / Almathera Ten on Ten - Disc 3: CDPD3.iso / scope / 101-125 / scopedisk109 / ms-dos / src / pack.c < prev    next >
C/C++ Source or Header  |  1995-03-19  |  32KB  |  1,056 lines

  1. /*-
  2.  * $Id: pack.c,v 1.3 90/02/03 17:02:05 Rhialto Exp $
  3.  * $Log:       pack.c,v $
  4.  * Revision 1.3  90/02/03  17:02:05  Rhialto
  5.  * Add error checking wrt dosalloc()
  6.  * 
  7.  * Revision 1.2  89/12/17  23:06:54  Rhialto
  8.  * Add ACTION_SET_PROTECT
  9.  *
  10.  * Revision 1.1  89/12/17  19:53:24  Rhialto
  11.  * Initial revision
  12.  *
  13.  *
  14.  *  Originally:
  15.  *
  16.  *     DOSDEVICE.C         V1.10   2 November 1987
  17.  *
  18.  *     EXAMPLE DOS DEVICE DRIVER FOR AZTEC.C   PUBLIC DOMAIN.
  19.  *
  20.  *     By Matthew Dillon.
  21.  *
  22.  *  This has been stripped and refilled with messydos code
  23.  *  by Olaf Seibert.
  24.  *
  25.  *  This code is (C) Copyright 1989 by Olaf Seibert. All rights reserved. May
  26.  *  not be used or copied without a licence.
  27.  *
  28.  *  Please note that we are NOT pure, so if you wish to mount
  29.  *  multiple MSDOS units, you must use different copies of this driver.
  30.  *
  31.  *  This file forms the interface between the actual handler code and all
  32.  *  AmigaDOS requirements. It shields it from ugly stuff like BPTRs, BSTRs,
  33.  *  FileLocks, FileHandles and VolumeNodes (in the form of DeviceLists).
  34.  *  Also, most protection against non-inserted disks is done here.
  35. -*/
  36.  
  37. #include "dos.h"
  38. #include "han.h"
  39.  
  40. #ifdef DEBUG
  41. #   define     debug(x)  dbprintf x
  42. #else
  43. #   define     debug(x)
  44. #endif
  45.  
  46. /*
  47.  * Since this code might be called several times in a row without being
  48.  * unloaded, you CANNOT ASSUME GLOBALS HAVE BEEN ZERO'D!!  This also goes
  49.  * for any global/static assignments that might be changed by running the
  50.  * code.
  51.  */
  52.  
  53. PORT          *DosPort;        /* Our DOS port... */
  54. DEVNODE        *DevNode;       /* Our DOS node.. created by DOS for us */
  55. DEVLIST        *VolNode;       /* Device List structure for our volume
  56.                                 * node */
  57.  
  58. void          *SysBase;        /* EXEC library base */
  59. DOSLIB        *DOSBase;        /* DOS library base for debug process */
  60. long           PortMask;       /* The signal mask for our DosPort */
  61. long           WaitMask;       /* The signal mask to wait for */
  62. short          DiskChanged;    /* Set by disk change interrupt */
  63. short          Inhibited;      /* Are we inhibited (ACTION_INHIBIT)? */
  64. long           UnitNr;         /* From */
  65. char          *DevName;        /*   the */
  66. ulong          DevFlags;       /*     mountlist */
  67. PACKET        *DosPacket;      /* For the SystemRequest pr_WindowPtr */
  68.  
  69. void ChangeIntHand(), DiskChange();
  70. void NewVolNodeName(), NewVolNodeDate();
  71.  
  72. struct Interrupt ChangeInt = {
  73.     { 0 },                     /* is_Node */
  74.     0,                         /* is_Data */
  75.     ChangeIntHand,             /* is_Code */
  76. };
  77.  
  78. /*
  79.  * Don't call the entry point main().  This way, if you make a mistake
  80.  * with the compile options you'll get a link error.
  81.  */
  82.  
  83. void
  84. messydoshandler()
  85. {
  86.     register PACKET *packet;
  87.     MSG           *msg;
  88.     byte           notdone;
  89.     long           OpenCount;      /* How many open files/locks there are */
  90.  
  91.     /*
  92.      * Initialize all global variables.  SysBase MUST be initialized
  93.      * before we can make Exec calls.  AbsExecBase is a library symbol
  94.      * referencing absolute memory location 4.
  95.      */
  96.  
  97.     SysBase = AbsExecBase;
  98.     DOSBase = OpenLibrary("dos.library", 0L);
  99.  
  100. #ifdef DEBUG
  101.     /*
  102.      * Initialize debugging code as soon as possible. Only SysBase and
  103.      * DOSBase are required.
  104.      */
  105.  
  106.     dbinit();
  107. #endif                         /* DEBUG */
  108.  
  109.     DosPort = &((struct Process *)FindTask(NULL))->pr_MsgPort;
  110.  
  111.     WaitPort(DosPort);      /* Get Startup Packet  */
  112.     msg = GetMsg(DosPort);
  113.     packet = (PACKET *) msg->mn_Node.ln_Name;
  114.  
  115.  
  116.     DevNode = BTOC(PArg3);
  117.     {
  118.        struct FileSysStartupMsg *fssm;
  119.        ulong *environ;
  120.  
  121.        DevName = "messydisk.device";
  122.        UnitNr = 0;
  123.        DevFlags = 0;
  124.  
  125.        MaxCache = 5;
  126.        BufMemType = MEMF_PUBLIC;
  127.        Disk.nsides = MS_NSIDES;
  128.        Disk.spt = MS_SPT;
  129.        Disk.bps = MS_BPS;
  130.        Disk.lowcyl = 0;
  131.  
  132.        if (fssm = (struct FileSysStartupMsg *)BTOC(DevNode->dn_Startup)) {
  133.                                    /* Same as BTOC(packet->dp_Arg2) */
  134.            UnitNr = fssm->fssm_Unit;
  135.            if (fssm->fssm_Device)
  136.                DevName = (char *)BTOC(fssm->fssm_Device)+1;
  137.            DevFlags = fssm->fssm_Flags;
  138.  
  139.            if (environ = BTOC(fssm->fssm_Environ)) {
  140.                debug(("environ size %ld\n", environ[0]));
  141. #define get(xx,yy)  if (environ[0] >= yy) xx = environ[yy];
  142.  
  143.                get(MaxCache, DE_NUMBUFFERS);
  144.                get(BufMemType, DE_MEMBUFTYPE);
  145.                get(Disk.nsides, DE_NUMHEADS);
  146.                get(Disk.spt, DE_BLKSPERTRACK);
  147.                get(Disk.bps, DE_SIZEBLOCK);
  148.                Disk.bps *= 4;
  149.                debug(("Disk.bps %d\n", Disk.bps));
  150.                get(Disk.lowcyl, DE_LOWCYL);
  151. #undef get
  152.            }
  153.        }
  154.        Disk.lowcyl *= (long)MS_BPS * Disk.spt * Disk.nsides;
  155.     }
  156.  
  157.     if (DOSBase && HanOpenUp()) {
  158.        /*
  159.         * Loading DevNode->dn_Task causes DOS *NOT* to startup a new
  160.         * instance of the device driver for every reference.   E.G. if
  161.         * you were writing a CON: device you would want this field to be
  162.         * NULL.
  163.         */
  164.  
  165.        DevNode->dn_Task = DosPort;
  166.  
  167.        PRes1 = DOSTRUE;
  168.        PRes2 = 0;
  169.     } else {               /* couldn't open dos.library  */
  170.        PRes1 = DOSFALSE;
  171.        PRes2 = ERROR_NO_FREE_STORE;    /* no better message available */
  172.        returnpacket(packet);
  173.        goto exit;              /* exit process    */
  174.     }
  175.     returnpacket(packet);
  176.  
  177.     /* Initialize some more global variables   */
  178.  
  179.     PortMask = 1L << DosPort->mp_SigBit;
  180.     VolNode = NULL;
  181.     OpenCount = 0;
  182.     Inhibited = 0;
  183.  
  184.     /* Get the first real packet       */
  185.     WaitPort(DosPort);
  186.     msg = GetMsg(DosPort);
  187.     notdone = 1;
  188.     WaitMask = PortMask | (1L << DiskReplyPort->mp_SigBit);
  189.     TDAddChangeInt(&ChangeInt);
  190.     DiskInserted(WhichDiskInserted());
  191.  
  192.     goto entry;
  193.  
  194.     /*
  195.      * Here begins the endless loop, waiting for requests over our message
  196.      * port and executing them.  Since requests are sent over the message
  197.      * port in our device and volume nodes, we must not use our Process
  198.      * message port for this: this precludes being able to call DOS
  199.      * functions ourselves.
  200.      */
  201.  
  202. top:
  203.     for (notdone = 1; notdone;) {
  204.        Wait(WaitMask);
  205.        if (DiskChanged)
  206.            DiskChange();
  207.        while (msg = GetMsg(DosPort)) {
  208.            byte            buf[256];   /* Max length of BCPL strings is
  209.                                         * 255 + 1 for \0. */
  210.  
  211.     entry:
  212.            if (DiskChanged)
  213.                DiskChange();
  214.            packet = (PACKET *) msg->mn_Node.ln_Name;
  215.            PRes1 = DOSFALSE;
  216.            PRes2 = 0;
  217.            error = 0;
  218.            debug(("Packet: %3ld %08lx %08lx %08lx %10s\n",
  219.                     PType, PArg1, PArg2, PArg3, typetostr(PType)));
  220.  
  221.            DosPacket = packet;         /* For the System Requesters */
  222.            switch (PType) {
  223.            case ACTION_DIE:            /* attempt to die?  */
  224.                notdone = 0;            /* try to die    */
  225.                break;
  226.            case ACTION_CURRENT_VOLUME: /* -                  VolNode,UnitNr */
  227.                PRes1 = (long) CTOB(VolNode);
  228.                PRes2 = UnitNr;
  229.                break;
  230.            case ACTION_LOCATE_OBJECT:  /* Lock,Name,Mode       Lock         */
  231.                {
  232.                    register struct FileLock *newlock;
  233.                    struct FileLock *lock;
  234.                    struct MSFileLock *msfl;
  235.                    long            lockmode;
  236.  
  237.                    lock = BTOC(PArg1);
  238.                    if (CheckRead(lock))
  239.                        break;
  240.                    btos(PArg2, buf);
  241.                    if ((lockmode = PArg3) != EXCLUSIVE_LOCK)
  242.                        lockmode = SHARED_LOCK;
  243.                    msfl = MSLock(lock ? lock->fl_Key : NULL,
  244.                                  buf,
  245.                                  lockmode);
  246.                    if (msfl) {
  247.                        if (newlock = NewFileLock(msfl, lock)) {
  248.                            newlock->fl_Access = lockmode;
  249.                            PRes1 = (long) CTOB(newlock);
  250.                            OpenCount++;
  251.                        } else
  252.                            MSUnLock(msfl);
  253.                    }
  254.                }
  255.                break;
  256.            case ACTION_RENAME_DISK:    /* BSTR:NewName            Bool      */
  257.                if (CheckWrite(NULL))
  258.                    break;
  259.                btos(PArg1, buf);
  260.                buf[31] = '\0';
  261.                if (PRes1 = MSRelabel(buf))
  262.                    NewVolNodeName();
  263.                break;
  264.            case ACTION_FREE_LOCK:      /* Lock                    Bool      */
  265.                {
  266.                    struct FileLock *lock;
  267.                    struct MSFileLock *msfl;
  268.  
  269.                    PRes1 = DOSTRUE;
  270.                    lock = BTOC(PArg1);
  271.                    if (lock == NULL)
  272.                        break;
  273.  
  274.                    msfl = (struct MSFileLock *)lock->fl_Key;
  275.                    FreeFileLock(lock); /* may remove last lock on volume */
  276.                    MSUnLock(msfl);     /* may call MayFreeVolNode */
  277.                    OpenCount--;
  278.                }
  279.                break;
  280.            case ACTION_DELETE_OBJECT:  /* Lock,Name            Bool         */
  281.                {
  282.                    struct FileLock *lock;
  283.  
  284.                    lock = BTOC(PArg1);
  285.                    if (CheckWrite(lock))
  286.                        break;
  287.                    btos(PArg2, buf);
  288.                    PRes1 = MSDeleteFile(lock ? lock->fl_Key : NULL,
  289.                                         buf);
  290.                }
  291.                break;
  292.            case ACTION_RENAME_OBJECT:  /* SLock,SName,DLock,DName   Bool    */
  293.                {
  294.                    struct FileLock *slock, *dlock;
  295.                    char             buf2[256];
  296.  
  297.                    slock = BTOC(PArg1);
  298.                    dlock = BTOC(PArg3);
  299.                    if (CheckWrite(slock) || CheckWrite(dlock))
  300.                        break;
  301.                    btos(PArg2, buf);
  302.                    btos(PArg4, buf2);
  303.                    PRes1 = MSRename(slock ? slock->fl_Key : NULL,
  304.                                     buf,
  305.                                     dlock ? dlock->fl_Key : NULL,
  306.                                     buf2);
  307.                }
  308.                break;
  309.            case ACTION_MORECACHE:      /* #BufsToAdd              Bool      */
  310.                if ((MaxCache += (short) PArg1) <= 0) {
  311.                    MaxCache = 1;
  312.                } else
  313.                    PRes1 = DOSTRUE;
  314.                debug(("Now %d cache sectors\n", MaxCache));
  315.                break;
  316.            case ACTION_COPY_DIR:       /* Lock                    Lock      */
  317.                {
  318.                    register struct FileLock *newlock;
  319.                    struct FileLock *lock;
  320.                    struct MSFileLock *msfl;
  321.  
  322.                    lock = BTOC(PArg1);
  323.  
  324.                    msfl = MSDupLock(lock ? lock->fl_Key : NULL);
  325.  
  326.                    if (msfl) {
  327.                        if (newlock = NewFileLock(msfl, lock)) {
  328.                            newlock->fl_Access =
  329.                                lock ? lock->fl_Access : SHARED_LOCK;
  330.                            PRes1 = (long) CTOB(newlock);
  331.                            OpenCount++;
  332.                        } else
  333.                            MSUnLock(msfl);
  334.                    }
  335.                }
  336.                break;
  337.            case ACTION_SET_PROTECT:    /* -,Lock,Name,Mask        Bool      */
  338.                {
  339.                    struct FileLock *lock;
  340.  
  341.                    lock = BTOC(PArg2);
  342.                    if (CheckWrite(lock))
  343.                        break;
  344.                    btos(PArg3, buf);
  345.                    PRes1 = MSSetProtect(lock ? lock->fl_Key : NULL, buf, PArg4);
  346.                }
  347.                break;
  348.            case ACTION_CREATE_DIR:     /* Lock,Name            Lock         */
  349.                {
  350.                    register struct FileLock *newlock;
  351.                    struct FileLock *lock;
  352.                    struct MSFileLock *msfl;
  353.  
  354.                    lock = BTOC(PArg1);
  355.                    if (CheckWrite(lock))
  356.                        break;
  357.                    btos(PArg2, buf);
  358.  
  359.                    msfl = MSCreateDir(lock ? lock->fl_Key : NULL, buf);
  360.  
  361.                    if (msfl) {
  362.                        if (newlock = NewFileLock(msfl, lock)) {
  363.                            newlock->fl_Access = SHARED_LOCK;
  364.                            PRes1 = (long) CTOB(newlock);
  365.                            OpenCount++;
  366.                        } else
  367.                            MSUnLock(msfl);
  368.                    }
  369.                }
  370.                break;
  371.            case ACTION_EXAMINE_OBJECT: /* Lock,Fib            Bool          */
  372.                {
  373.                    struct FileLock *lock;
  374.  
  375.                    lock = BTOC(PArg1);
  376.                    if (CheckRead(lock))
  377.                        break;
  378.                    PRes1 = MSExamine(lock ? lock->fl_Key : NULL, BTOC(PArg2));
  379.                }
  380.                break;
  381.            case ACTION_EXAMINE_NEXT:   /* Lock,Fib            Bool          */
  382.                {
  383.                    struct FileLock *lock;
  384.  
  385.                    lock = BTOC(PArg1);
  386.                    if (CheckRead(lock))
  387.                        break;
  388.                    PRes1 = MSExNext(lock ? lock->fl_Key : NULL, BTOC(PArg2));
  389.                }
  390.                break;
  391.            case ACTION_DISK_INFO:      /* InfoData            Bool:TRUE     */
  392.                PRes1 = MSDiskInfo(BTOC(PArg1));
  393.                break;
  394.            case ACTION_INFO:   /* Lock,InfoData               Bool:TRUE     */
  395.                if (CheckRead(BTOC(PArg1)))
  396.                    break;
  397.                PRes1 = MSDiskInfo(BTOC(PArg2));
  398.                break;
  399.            case ACTION_FLUSH:          /* writeout bufs, disk motor off     */
  400.                MSUpdate(1);
  401.                break;
  402. /*         case ACTION_SET_COMMENT:    /* -,Lock,Name,Comment     Bool      */
  403.            case ACTION_PARENT: /* Lock                        ParentLock    */
  404.                {
  405.                    register struct FileLock *newlock;
  406.                    struct FileLock *lock;
  407.                    struct MSFileLock *msfl;
  408.                    long mode;
  409.  
  410.                    lock = BTOC(PArg1);
  411.  
  412.                    msfl = MSParentDir(lock ? lock->fl_Key : NULL);
  413.  
  414.                    if (msfl) {
  415.                        if (newlock = NewFileLock(msfl, lock)) {
  416.                            newlock->fl_Access = SHARED_LOCK;
  417.                            PRes1 = (long) CTOB(newlock);
  418.                            OpenCount++;
  419.                        } else
  420.                            MSUnLock(msfl);
  421.                    }
  422.                }
  423.                break;
  424.            case ACTION_INHIBIT:        /* Bool                    Bool      */
  425.                if (Inhibited = PArg1) {
  426.                    DiskRemoved();
  427.                } else { /* Fall through to ACTION_DISK_CHANGE: */
  428.            case ACTION_DISK_CHANGE:    /* ?                       ?         */
  429.                    DiskChange();
  430.                }
  431.                PRes1 = DOSTRUE;
  432.                break;
  433.            case ACTION_SET_DATE: /* -,Lock,Name,CPTRDateStamp     Bool      */
  434.                {
  435.                    struct FileLock *lock;
  436.  
  437.                    lock = BTOC(PArg2);
  438.                    if (CheckWrite(lock))
  439.                        break;
  440.                    btos(PArg3, buf);
  441.                    PRes1 = MSSetDate(lock ? lock->fl_Key : NULL,
  442.                                      buf,
  443.                                      PArg4);
  444.                }
  445.                break;
  446.            case ACTION_READ:   /* FHArg1,CPTRBuffer,Length       ActLength  */
  447.                if (CheckRead(NULL)) {
  448.                    PRes1 = -1;
  449.                } else
  450.                    PRes1 = MSRead(PArg1, PArg2, PArg3);
  451.                break;
  452.            case ACTION_WRITE:  /* FHArg1,CPTRBuffer,Length       ActLength  */
  453.                if (CheckWrite(NULL)) {
  454.                    PRes1 = -1;
  455.                } else
  456.                    PRes1 = MSWrite(PArg1, PArg2, PArg3);
  457.                break;
  458.            case ACTION_OPENNEW:        /* FileHandle,Lock,Name    Bool      */
  459.                {
  460.                    struct MSFileHandle *msfh;
  461.                    struct FileHandle *fh;
  462.                    struct FileLock *lock;
  463.  
  464.                    if (CheckWrite(BTOC(PArg2)))
  465.                        break;
  466.            case ACTION_OPENRW:         /* FileHandle,Lock,Name    Bool      */
  467.            case ACTION_OPENOLD:        /* FileHandle,Lock,Name    Bool      */
  468.  
  469.                    fh = BTOC(PArg1);
  470.                    lock = BTOC(PArg2);
  471.                    if (CheckRead(lock))
  472.                        break;
  473.                    btos(PArg3, buf);
  474.                    debug(("'%s' ", buf));
  475.                    msfh = MSOpen(lock ? lock->fl_Key : NULL,
  476.                                  buf,
  477.                                  PType);
  478.                    if (msfh) {
  479.                        fh->fh_Arg1 = (long) msfh;
  480.                        PRes1 = DOSTRUE;
  481.                        OpenCount++;
  482.                    }
  483.                }
  484.                break;
  485.            case ACTION_CLOSE:  /* FHArg1                         Bool:TRUE  */
  486.                MSClose(PArg1);
  487.                PRes1 = DOSTRUE;
  488.                OpenCount--;
  489.                break;
  490.            case ACTION_SEEK:   /* FHArg1,Position,Mode          OldPosition */
  491.                if (CheckRead(NULL)) {
  492.                    PRes1 = -1;
  493.                } else
  494.                    PRes1 = MSSeek(PArg1, PArg2, PArg3);
  495.                break;
  496.                /*
  497.                 * A few other packet types which we do not support
  498.                 */
  499. /*         case ACTION_WAIT_CHAR:      /* Timeout, ticks          Bool      */
  500. /*         case ACTION_RAWMODE:        /* Bool(-1:RAW 0:CON)      OldState  */
  501.            default:
  502.                error = ERROR_ACTION_NOT_KNOWN;
  503.                break;
  504.            } /* end switch */
  505.            if (packet) {
  506.                if (error) {
  507.                    debug(("ERR=%d\n", error));
  508.                    PRes2 = error;
  509.                }
  510. #ifdef DEBUG
  511.                else {
  512.                    debug(("RES=%06lx\n", PRes1));
  513.                }
  514. #endif
  515.                returnpacket(packet);
  516.                DosPacket = NULL;
  517.            }
  518. #ifdef DEBUG
  519.            else {
  520.                debug(("NOREP\n"));
  521.            }
  522. #endif
  523.        } /* end while (GetMsg()) */
  524.  
  525.        /*
  526.         *  Now check for an other cause of events: timer IO.
  527.         *  Unfortunately we cannot be sure that we always get a signal
  528.         *  when the timeout has elapsed, since the same message port is
  529.         *  used for other IO.
  530.         */
  531.        if (CheckIO(TimeIOReq)) {   /* Timer finished? */
  532.            debug(("TimeIOReq is finished\n"));
  533.            if (DelayState != DELAY_OFF) {
  534.                MSUpdate(0);    /* Also may switch off motor */
  535.            }
  536.        }
  537.     } /* end for (;notdone) */
  538.  
  539. #ifdef DEBUG
  540.     debug(("Can we remove ourselves? "));
  541.     Delay(50L);                 /* I wanna even see the debug message! */
  542. #endif                         /* DEBUG */
  543.     Forbid();
  544.     if (OpenCount || packetsqueued()) {
  545.        Permit();
  546.        debug((" ..  not yet!\n"));
  547.        goto top;               /* sorry... can't exit     */
  548.     }
  549.     debug((" .. yes!\n"));
  550.  
  551.     /*
  552.      * Causes a new process to be created on next reference.
  553.      */
  554.  
  555.     DevNode->dn_Task = NULL;
  556.     TDRemChangeInt();
  557.     DiskRemoved();
  558.     HanCloseDown();
  559.     debug(("HanCloseDown returned. dbuninit in 2 seconds:\n"));
  560.  
  561.     /*
  562.      * Remove debug window, closedown, fall of the end of the world.
  563.      */
  564. exit:
  565. #ifdef DEBUG
  566.     Delay(100L);                /* This is dangerous! */
  567.     dbuninit();
  568. #endif                         /* DEBUG */
  569.  
  570. #if 1
  571.     UnLoadSeg(DevNode->dn_SegList);     /* This is real fun. We are still */
  572.     DevNode->dn_SegList = NULL;        /* Forbid()den, fortunately */
  573. #endif
  574.  
  575.     CloseLibrary(DOSBase);
  576.  
  577.     /* Fall off the end of the world. Implicit Permit(). */
  578. }
  579.  
  580. void
  581. ChangeIntHand()
  582. {
  583. /* INDENT OFF */
  584. #asm
  585.     move.l  a6,-(sp)
  586. #endasm
  587.     DiskChanged = 1;
  588.     Signal(DosPort->mp_SigTask, PortMask);
  589. #asm
  590.     move.l  (sp)+,a6
  591. #endasm
  592. /* INDENT ON */
  593. }
  594.  
  595. /*
  596.  *  Make a new struct FileLock, for DOS use. It is put on a singly linked
  597.  *  list, which is attached to the same VolumeNode the old lock was on.
  598.  *
  599.  *  Also note that we must ALWAYS be prepared to UnLock() or DupLock()
  600.  *  any FileLocks we ever made, even if the volume in question has been
  601.  *  removed and/or inserted into another drive with another FileSystem
  602.  *  handler!
  603.  *
  604.  * DOS makes certain assumptions about LOCKS.  A lock must minimally be a
  605.  * FileLock structure, with additional private information after the
  606.  * FileLock structure. The longword before the beginning of the structure
  607.  * must contain the length of structure + 4.
  608.  *
  609.  * NOTE!!!!! The workbench does not follow the rules and assumes it can copy
  610.  * lock structures.  This means that if you want to be workbench
  611.  * compatible, your lock structures must be EXACTLY sizeof(struct
  612.  * FileLock). Also, it sometimes uses uninitialized values for the lock mode...
  613.  */
  614.  
  615. struct FileLock *
  616. NewFileLock(msfl, fl)
  617. struct MSFileLock *msfl;
  618. struct FileLock *fl;
  619. {
  620.     struct FileLock *newlock;
  621.     DEVLIST *volnode;
  622.  
  623.     if (fl) {
  624.        volnode = BTOC(fl->fl_Volume);
  625.     } else {
  626.        volnode = VolNode;
  627.     }
  628.  
  629.     if (newlock = dosalloc((ulong)sizeof (*newlock))) {
  630.        newlock->fl_Key = (ulong) msfl;
  631.        newlock->fl_Task = DosPort;
  632.        newlock->fl_Volume = (BPTR) CTOB(volnode);
  633.        Forbid();
  634.        newlock->fl_Link = volnode->dl_LockList;
  635.        volnode->dl_LockList = (BPTR) CTOB(newlock);
  636.        Permit();
  637.     } else
  638.        error = ERROR_NO_FREE_STORE;
  639.  
  640.     return newlock;
  641. }
  642.  
  643. /*
  644.  *  This should be called before MSUnLock(), so that it may call
  645.  *  MayFreeVolNode() which then calls FreeVolNode(). A bit tricky,
  646.  *  I'm sorry for that.
  647.  */
  648.  
  649. long
  650. FreeFileLock(lock)
  651. struct FileLock *lock;
  652. {
  653.     register struct FileLock *fl;
  654.     register struct FileLock **flp;
  655.     DEVLIST       *volnode;
  656.  
  657.     volnode = (DEVLIST *)BTOC(lock->fl_Volume);
  658.     flp = (struct FileLock **) &volnode->dl_LockList;
  659.     for (fl = BTOC(*flp); fl && fl != lock; fl = BTOC(fl->fl_Link))
  660.        flp = (struct FileLock **)&fl->fl_Link;
  661.  
  662.     if (fl == lock) {
  663.        *(BPTR *)flp = fl->fl_Link;
  664.        dosfree(fl);
  665.        return DOSTRUE;
  666.     } else {
  667.        debug(("Huh?? Could not find filelock!\n"));
  668.        return DOSFALSE;
  669.     }
  670. }
  671.  
  672. /*
  673.  * Create Volume node and add to the device list.   This will
  674.  * cause the WORKBENCH to recognize us as a disk.   If we
  675.  * don't create a Volume node, Wb will not recognize us.
  676.  * However, we are a MESSYDOS: disk, Volume node or not.
  677.  */
  678.  
  679. DEVLIST        *
  680. NewVolNode(name, date)
  681. struct DateStamp *date;
  682. char *name;
  683. {
  684.     DOSINFO       *di;
  685.     register DEVLIST *volnode;
  686.     char          *volname;        /* This is my volume name */
  687.  
  688.     di = BTOC(((ROOTNODE *) DOSBase->dl_Root)->rn_Info);
  689.  
  690.     if (volnode = dosalloc((ulong)sizeof (DEVLIST))) {
  691.        if (volname = dosalloc(32L)) {
  692.            volname[0] = strlen(name);
  693.            strcpy(volname + 1, name);      /* Make sure \0 terminated */
  694.  
  695.            volnode->dl_Type = DLT_VOLUME;
  696.            volnode->dl_Task = DosPort;
  697.            volnode->dl_DiskType = IDDiskType;
  698.            volnode->dl_Name = CTOB(volname);
  699.            volnode->dl_VolumeDate = *date;
  700.            volnode->dl_MSFileLockList = NULL;
  701.  
  702.            Forbid();
  703.            volnode->dl_Next = di->di_DevInfo;
  704.            di->di_DevInfo = (long) CTOB(volnode);
  705.            Permit();
  706.        } else {
  707.            dosfree(volnode);
  708.            volnode = NULL;
  709.        }
  710.     } else {
  711.        error = ERROR_NO_FREE_STORE;
  712.     }
  713.  
  714.     return volnode;
  715. }
  716.  
  717. /*
  718.  *  Get the current VolNode a new name from the volume label.
  719.  */
  720.  
  721. void
  722. NewVolNodeName()
  723. {
  724.     if (VolNode) {
  725.        register char *volname = BTOC(VolNode->dl_Name);
  726.  
  727.        strncpy(volname + 1, Disk.vollabel.de_Msd.msd_Name, 8+3);
  728.        volname[1+8+3] = '\0';      /* Make sure \0 terminated */
  729.        ZapSpaces(volname + 1, volname + 1 + 8+3);
  730.        volname[0] = strlen(volname+1);
  731.     }
  732. }
  733.  
  734. /*
  735.  *  Get the current VolNode a new date, from the last root directory.
  736.  */
  737.  
  738. void
  739. NewVolNodeDate()
  740. {
  741.     if (VolNode) {
  742.        ToDateStamp(&VolNode->dl_VolumeDate,
  743.                    Disk.vollabel.de_Msd.msd_Date,
  744.                    Disk.vollabel.de_Msd.msd_Time);
  745.     }
  746. }
  747.  
  748. /*
  749.  * Remove Volume entry.  Since DOS uses singly linked lists, we must
  750.  * (ugg) search it manually to find the link before our Volume entry.
  751.  */
  752.  
  753. void
  754. FreeVolNode(volnode)
  755. DEVLIST        *volnode;
  756. {
  757.     DOSINFO       *di = BTOC(((ROOTNODE *) DOSBase->dl_Root)->rn_Info);
  758.     register DEVLIST *dl;
  759.     register void  *dlp;
  760.  
  761.     debug(("FreeVolNode %08lx\n", volnode));
  762.  
  763.     if (volnode == NULL)
  764.        return;
  765.  
  766.     dlp = &di->di_DevInfo;
  767.     Forbid();
  768.     for (dl = BTOC(di->di_DevInfo); dl && dl != volnode; dl = BTOC(dl->dl_Next))
  769.        dlp = &dl->dl_Next;
  770.     if (dl == volnode) {
  771.        *(BPTR *) dlp = dl->dl_Next;
  772.        dosfree(BTOC(dl->dl_Name));
  773.        dosfree(dl);
  774.     }
  775. #ifdef DEBUG
  776.     else {
  777.        debug(("****PANIC: Unable to find volume node\n"));
  778.     }
  779. #endif                         /* DEBUG */
  780.     Permit();
  781.  
  782.     if (volnode == VolNode)
  783.        VolNode = NULL;
  784. }
  785.  
  786. /*
  787.  *  This is also called from the real handler when the last lock on a
  788.  *  volume is UnLock()ed, or the last file has been Close()d.
  789.  */
  790.  
  791. int
  792. MayFreeVolNode(volnode)
  793. DEVLIST *volnode;
  794. {
  795.     if (volnode->dl_LockList == NULL) {
  796.        FreeVolNode(volnode);
  797.        return 1;
  798.     }
  799.  
  800.     return 0;
  801. }
  802.  
  803. /*
  804.  *  Our disk has been removed. Save the FileLocks in the dl_LockList,
  805.  *  and let the handler save its MSFileLocks in the dl_MSFileLockList field.
  806.  *  If it has nothing to save, forget about the volume, and return
  807.  *  DOSTRUE.
  808.  *  There is one subtlety that MSDiskRemoved must know about:
  809.  *  If it MSUnLock()s the last lock on the volume, the VolNode is
  810.  *  deleted via FreeLockList().. MayFreeVolNode().. FreeVolNode().
  811.  *  But then there is no place anymore to put NULL in, so that needs
  812.  *  to be done first.
  813.  */
  814.  
  815. int
  816. DiskRemoved()
  817. {
  818.     debug(("DiskRemoved %08lx\n", VolNode));
  819.  
  820.     if (VolNode == NULL) {
  821.        IDDiskType = ID_NO_DISK_PRESENT;/* really business of MSDiskRemoved */
  822.        return DOSTRUE;
  823.     }
  824.  
  825.     VolNode->dl_Task = NULL;
  826.     MSDiskRemoved(&VolNode->dl_MSFileLockList);
  827.     if (VolNode == NULL) {  /* Could happen via MSDiskRemoved() */
  828.        return DOSTRUE;
  829.     }
  830.     NewVolNodeDate();       /* Fetch new date of root directory */
  831.     VolNode = NULL;
  832.     return DOSFALSE;
  833. }
  834.  
  835. /*
  836.  *  Reconstruct everything from a Volume node
  837.  */
  838.  
  839. void
  840. DiskInserted(volnode)
  841. register DEVLIST       *volnode;
  842. {
  843.     debug(("DiskInserted %08lx\n", volnode));
  844.  
  845.     VolNode = volnode;
  846.  
  847.     if (volnode) {
  848.        volnode->dl_Task = DosPort;
  849.        MSDiskInserted(&volnode->dl_MSFileLockList, volnode);
  850.        volnode->dl_MSFileLockList = NULL;
  851.     }
  852. }
  853.  
  854. DEVLIST *
  855. WhichDiskInserted()
  856. {
  857.     char name[34];
  858.     struct DateStamp date;
  859.     register DEVLIST *dl = NULL;
  860.  
  861.     if (!Inhibited && IdentifyDisk(name, &date) == 0) {
  862.        DOSINFO        *di = BTOC(((ROOTNODE *) DOSBase->dl_Root)->rn_Info);
  863.        byte           *nodename;
  864.        int             namelen = strlen(name);
  865.  
  866.        for (dl = BTOC(di->di_DevInfo); dl; dl = BTOC(dl->dl_Next)) {
  867.            nodename = BTOC(dl->dl_Name);
  868.            if (nodename[0] != namelen || strncmp(nodename+1,name,namelen))
  869.                continue;
  870.            if (dl->dl_VolumeDate == date)  /* Non-standard! Structure compare! */
  871.                break;
  872.        }
  873.  
  874.        name[31] = '\0';
  875.        if (dl == NULL)
  876.            dl = NewVolNode(name, &date);
  877.     }
  878.  
  879.     return dl;
  880. }
  881.  
  882. void
  883. DiskChange()
  884. {
  885.     debug(("DiskChange\n"));
  886.     DiskChanged = 0;
  887.     DiskRemoved();
  888.     DiskInserted(WhichDiskInserted());
  889. }
  890.  
  891. int
  892. CheckRead(lock)
  893. struct FileLock *lock;
  894. {
  895.     if (lock && BTOC(lock->fl_Volume) != VolNode)
  896.        error = ERROR_DEVICE_NOT_MOUNTED;
  897.     else if (IDDiskType == ID_NO_DISK_PRESENT)
  898.        error = ERROR_NO_DISK;
  899.     else if (IDDiskType != ID_DOS_DISK)
  900.        error = ERROR_NOT_A_DOS_DISK;
  901.  
  902.     return error;
  903. }
  904.  
  905. int
  906. CheckWrite(lock)
  907. struct FileLock *lock;
  908. {
  909.     if (lock && BTOC(lock->fl_Volume) != VolNode)
  910.        error = ERROR_DEVICE_NOT_MOUNTED;
  911.     else if (IDDiskType == ID_NO_DISK_PRESENT)
  912.        error = ERROR_NO_DISK;
  913.     else if (IDDiskType != ID_DOS_DISK)
  914.        error = ERROR_NOT_A_DOS_DISK;
  915.     else if (IDDiskState == ID_VALIDATING)
  916.        error = ERROR_DISK_NOT_VALIDATED;
  917.     else if (IDDiskState != ID_VALIDATED)
  918.        error = ERROR_DISK_WRITE_PROTECTED;
  919.  
  920.     return error;
  921. }
  922.  
  923. #ifdef DEBUG
  924.                    /*  DEBUGGING                       */
  925. PORT *Dbport;      /*  owned by the debug process      */
  926. PORT *Dback;       /*  owned by the DOS device driver  */
  927. short DBEnable;
  928.  
  929. /*
  930.  *  DEBUGGING CODE.    You cannot make DOS library calls that access other
  931.  *  devices from within a DOS device driver because they use the same
  932.  *  message port as the driver.  If you need to make such calls you must
  933.  *  create a port and construct the DOS messages yourself.  I do not
  934.  *  do this.  To get debugging info out another PROCESS is created to which
  935.  *  debugging messages can be sent.
  936.  */
  937.  
  938. extern void debugproc();
  939.  
  940. dbinit()
  941. {
  942.     TASK *task = FindTask(NULL);
  943.  
  944.     Dback = CreatePort("MSH:Dback", -1L);
  945.     CreateProc("MSH_DB", (long)task->tc_Node.ln_Pri+1, CTOB(debugproc), 4096L);
  946.     WaitPort(Dback);                                /* handshake startup    */
  947.     GetMsg(Dback);                                  /* remove dummy msg     */
  948.     DBEnable = 1;
  949.     dbprintf("Debugger running V1.10\n");
  950. }
  951.  
  952. dbuninit()
  953. {
  954.     MSG killmsg;
  955.  
  956.     if (Dbport) {
  957.        killmsg.mn_Length = 0;      /*  0 means die         */
  958.        PutMsg(Dbport,  &killmsg);
  959.        WaitPort(Dback);            /*  He's dead jim!      */
  960.        GetMsg(Dback);
  961.        DeletePort(Dback);
  962.  
  963.        /*
  964.         *  Since the debug process is running at a greater priority, I
  965.         *  am pretty sure that it is guarenteed to be completely removed
  966.         *  before this task gets control again.  Still, it doesn't hurt...
  967.         */
  968.  
  969.        Delay(50L);                 /*  ensure he's dead    */
  970.     }
  971. }
  972.  
  973. dbprintf(a,b,c,d,e,f,g,h,i,j)
  974. long a,b,c,d,e,f,g,h,i,j;
  975. {
  976.     struct {
  977.        MSG     msg;
  978.        char    buf[256];
  979.     } msgbuf;
  980.     register MSG *msg = &msgbuf.msg;
  981.     register long len;
  982.  
  983.     if (Dbport && DBEnable) {
  984.        sprintf(msgbuf.buf,a,b,c,d,e,f,g,h,i,j);
  985.        len = strlen(msgbuf.buf)+1;
  986.        msg->mn_Length = len;   /*  Length NEVER 0  */
  987.        PutMsg(Dbport, msg);
  988.        WaitPort(Dback);
  989.        GetMsg(Dback);
  990.     }
  991. }
  992.  
  993. /*
  994.  *  BTW, the DOS library used by debugmain() was actually opened by
  995.  *  the device driver.
  996.  */
  997.  
  998. debugmain()
  999. {
  1000.     register MSG *msg;
  1001.     register long len;
  1002.     register void *fh;
  1003.     void *fh2;
  1004.     MSG DummyMsg;
  1005.  
  1006.     Dbport = CreatePort("MSH:Dbport", -1L);
  1007.     fh = Open("CON:0/10/640/190/FileSystem debug", MODE_NEWFILE);
  1008.     fh2 = Open("PAR:", MODE_OLDFILE);
  1009.     PutMsg(Dback, &DummyMsg);
  1010.     for (;;) {
  1011.        WaitPort(Dbport);
  1012.        msg = GetMsg(Dbport);
  1013.        len = msg->mn_Length;
  1014.        if (len == 0)
  1015.            break;
  1016.        --len;                      /*  Fix length up   */
  1017.        if (DBEnable & 1)
  1018.            Write(fh, msg+1, len);
  1019.        if (DBEnable & 2)
  1020.            Write(fh2, msg+1, len);
  1021.        PutMsg(Dback, msg);
  1022.     }
  1023.     Close(fh);
  1024.     Close(fh2);
  1025.     DeletePort(Dbport);
  1026.     PutMsg(Dback, msg);             /*  Kill handshake  */
  1027. }
  1028.  
  1029. /*
  1030.  *  The assembly tag for the DOS process:  CNOP causes alignment problems
  1031.  *  with the Aztec assembler for some reason.  I assume then, that the
  1032.  *  alignment is unknown.  Since the BCPL conversion basically zero's the
  1033.  *  lower two bits of the address the actual code may start anywhere
  1034.  *  within 8 bytes of address (remember the first longword is a segment
  1035.  *  pointer and skipped).  Sigh....  (see CreateProc() above).
  1036.  */
  1037.  
  1038. #asm
  1039.        public  _debugproc
  1040.        public  _debugmain
  1041.  
  1042.        cseg
  1043. _debugproc:
  1044.        nop
  1045.        nop
  1046.        nop
  1047.        nop
  1048.        nop
  1049.        movem.l D2-D7/A2-A6,-(sp)
  1050.        jsr     _debugmain
  1051.        movem.l (sp)+,D2-D7/A2-A6
  1052.        rts
  1053. #endasm
  1054.  
  1055. #endif                         /* DEBUG */
  1056.